"""
pip install 01 numpy
pip install 02 pandas
pip install 03 matplotlib
pip install xlsxwriter
pip install openpyxl
pip install gzip
"""

import datetime
import gzip
import os

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

plt.rcParams['font.sans-serif'] = ['KaiTi']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题


def interface_stats(log_path):
    """
     统计接口调用次数
    :param log_path: 日志文件路径
    :return: 接口统计次数字典
    """
    df = pd.read_csv(log_path, sep=" ",  # 空格读取
                     names=(np.arange(0, 29)),  # 列名暂定
                     low_memory=False
                     ).dropna(axis=0)  # 数据清洗
    result = pd.DataFrame(df.groupby(by=[12]).size())  # 根据第12列分组
    result['接口名称'] = None
    for i in result.index:
        url = str(i).split(' ')[1]
        if url.startswith('https://'):
            url = url.split('https://')[1]
        elif url.startswith('http://'):
            url = url.split('http://')[1]
        else:
            continue
        method = url[url.find('/'):]
        result['接口名称'].at[i] = method[:method.find('?')] if method.find('?') != -1 else method
    dict_ = {}
    for i in result.index:
        method = result['接口名称'].at[i]
        new = result[0].at[i]
        old = dict_.get(method)
        dict_[method] = new if old is None else new + dict_.get(method)
    return dict_


def interface_stats_to_excel(writer, dict_, sheet_name, wide):
    """接口统计报表生成"""
    dict_['合计'] = np.array(list(dict_.values())).sum()
    result = pd.DataFrame({'请求次数': list(dict_.values())}, index=list(dict_.keys())).sort_values(by=['请求次数'])
    result.index.name = '接口名称'
    result.to_excel(writer, sheet_name=sheet_name, encoding='utf8')
    sheet = writer.sheets[sheet_name]
    sheet.set_column('A:A', wide)
    sheet.set_column('B:B', 10)


def interface_stats_to_image(result_path, sheet_name, y_fontsize):
    """
    接口统计柱状图生成
    :param result_path: 统计结果文件路径
    :param sheet_name: sheet_name
    :param y_fontsize: y轴字体大小
    """
    df = pd.read_excel(result_path + '分析结果.xlsx', sheet_name=sheet_name)[:-1]  # 去掉最后一行合计
    x, y = df['接口名称'], df['请求次数']  # x轴显示接口名称,y轴显示请求次数
    plt.figure(dpi=500, facecolor='orange', edgecolor='black')  # 设置图片大小,背景色,柱状图边框颜色
    # 竖直显示
    plt.barh(x, y, color=['r', 'b', 'g', 'y', 'k'])  # 柱状图颜色列表
    plt.xlabel('请求次数')  # x轴文言
    plt.ylabel('接口名称')  # y轴文言
    for a, b in zip(x, y):  # 柱状图上面加上具体请求次数
        plt.text(b, a, b, ha='left', verticalalignment='center', fontsize=4)
    plt.yticks(fontsize=y_fontsize, color='#000000')  # x轴字体
    plt.xticks(fontsize=10, color='#000000')  # x轴字体
    plt.title(sheet_name, size=20)  # 标题
    # 布局
    plt.tight_layout()
    plt.savefig('%s%s.png' % (result_path, sheet_name))  # 保存图片


def merge(dict_1, dict_2):
    """合并两个字典,相同key的值相加，不同的新增"""
    for method in dict_1:
        new = dict_2.get(method)
        old = dict_1.get(method)
        dict_1[method] = old if new is None else new + old
    return dict_1


def analyse_file(f_path_list, result_path):
    """
    分析日志文件
    :param f_path_list: 日志文件路径列表
    :param result_path: 统计接口文件路径
    """
    dict_ = None
    for index, value in enumerate(f_path_list):
        dict_ = interface_stats(value) if dict_ is None else merge(dict_, interface_stats(value))
        print('第%d/%d个文件分析完成' % (index + 1, len(f_path_list)))
    dict_v1 = {key: dict_[key] for key in dict_ if
               key.find('.') == -1 and not key.startswith('/v2/') and not key.startswith(
                   '/ota/') and not key.startswith('/datacollect/')}
    dict_ota = {key: dict_[key] for key in dict_ if key.find('.') == -1 and key.startswith('/ota/')}
    dict_collect = {key: dict_[key] for key in dict_ if key.find('.') == -1 and key.startswith('/datacollect/')}
    dict_v2 = {key: dict_[key] for key in dict_ if key.find('.') == -1 and key.startswith('/v2/')}
    dict_static = {key: dict_[key] for key in dict_ if key.find('.') != -1}
    dict_compare = {
        'v1接口': np.array(list(dict_v1.values())).sum(),
        'v2接口': np.array(list(dict_v2.values())).sum(),
        'ota接口': np.array(list(dict_ota.values())).sum(),
        '数据采集接口': np.array(list(dict_collect.values())).sum(),
        '静态文件': np.array(list(dict_static.values())).sum()
    }
    writer = pd.ExcelWriter(result_path + '分析结果.xlsx', engine='xlsxwriter')
    print('统计报表生成中..........')
    interface_stats_to_excel(writer, dict_, '全部接口统计', 80)
    interface_stats_to_excel(writer, dict_compare, '对比统计', 30)
    interface_stats_to_excel(writer, dict_v1, 'v1接口统计', 80)
    interface_stats_to_excel(writer, dict_v2, 'v2接口统计', 80)
    interface_stats_to_excel(writer, dict_ota, 'ota接口统计', 80)
    interface_stats_to_excel(writer, dict_collect, '数据采集接口统计', 80)
    interface_stats_to_excel(writer, dict_static, '静态文件统计', 80)
    # 保存
    writer.save()
    # 生成图片
    print('统计图片生成中..........')
    interface_stats_to_image(result_path, '全部接口统计', 3)
    interface_stats_to_image(result_path, 'v1接口统计', 5)
    interface_stats_to_image(result_path, 'v2接口统计', 5)
    interface_stats_to_image(result_path, '数据采集接口统计', 6)


def unzip_file(dir_path):
    """
    解压缩日志文件
    :param dir_path: 日志文件文件夹路径
    :return: 所有日志文件路径列表
    """
    gz_file_list = [name for name in os.listdir(dir_path) if name.endswith('.gz')
                    and not os.path.exists(dir_path + name.replace(".gz", ""))]
    if len(gz_file_list) > 0:
        print('解压文件中..........')
        for index, old_name in enumerate(gz_file_list):
            new_name = old_name.replace(".gz", "")
            g_file = gzip.GzipFile(dir_path + old_name)
            open(dir_path + new_name, "wb+").write(g_file.read())
            g_file.close()
            print('第%d/%d个文件解压完成' % (index + 1, len(gz_file_list)))
    return [dir_path + name for name in os.listdir(dir_path) if name.endswith('.log')]


if __name__ == '__main__':
    # 处理用户输入的日志文件路径
    while True:
        file_path = input('请输入日志文件/文件夹路径: ')
        if os.path.exists(file_path):
            file_path_list = unzip_file(file_path) if os.path.isdir(file_path) else [file_path]
            break
        else:
            print('文件/文件不存在')

    # 处理用户输入的统计结果路径
    while True:
        result_path = input('请输入统计结果路径(按enter键默认): ')
        if not os.path.isdir(result_path):
            if result_path == '':
                result_path = 'result/'
                break
        else:
            break
    if not os.path.exists(result_path): os.makedirs(result_path)

    # 日志分析
    start = datetime.datetime.now()
    print('-------日志分析开始: %s.......' % start.strftime('%Y/%m/%d %H:%M:%S'))
    analyse_file(file_path_list, result_path)
    end = datetime.datetime.now()
    print('-------日志分析结束: %s-------' % end.strftime('%Y/%m/%d %H:%M:%S'))
    print('耗时%.2f秒' % float(end.timestamp() - start.timestamp()))
